﻿using Newtonsoft.Json;
using PropertyChanged;
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Input;
using VIA.Foundation;
using VIA.Integration.LeadShine.Presentation.Properties;
using VIA.Presentation;

namespace VIA.Integration.LeadShine.Presentation
{
    [AddINotifyPropertyChangedInterface]
    public class AxisDebugOption
    {
        //double _absPosition;
        //double _relPosition;
        //double _continueSpeed = 1;
        //double _jogSpeed = 1;
        //public double AbsPosition
        //{
        //    get => _absPosition;
        //    set => SetProperty(ref _absPosition, value);
        //}
        //public double RelPosition
        //{
        //    get => _relPosition;
        //    set => SetProperty(ref _relPosition, value);
        //}
        //public double ContinueSpeed
        //{
        //    get => _continueSpeed;
        //    set => SetProperty(ref _continueSpeed, value);
        //}
        //public double JogSpeed
        //{
        //    get => _jogSpeed;
        //    set => SetProperty(ref _jogSpeed, value);
        //}
        public double AbsPosition { get; set; }
        public double RelPosition { get; set; }
        public double ContinueSpeed { get; set; }
        public double JogSpeed { get; set; }
    }
    public class AxisModel : Model
    {
        #region Fields
        ITypeAdapter _typeAdapter;
        DmcAxis _axis;
        private double _current;
        private double _equivalent;
        private int _noId;
        private double _speed = 1;
        double _currentSpeed;
        double tdec = 0.1;
        double _tacc = 0.1;
        double maxvel;


        private bool _isAlm;
        private bool _isEmg;
        private bool _isMel;
        private bool _isOrg;
        private bool _isPel;
        private bool isParamEnable;
        #endregion

        #region MyRegion
        public string Name => _axis == null ? null : _axis.Name;
        public string Channel => _axis == null ? "CHNull" : $"CH{_axis.NoId + 1}";
        public int NoId
        {
            get => _noId;
            set
            {
                if (SetProperty(ref _noId, value))
                {
                    _axis.NoId = value;
                }
            }
        }

        double _homeOffset;
        VelocityCurveModel _defaultVelocityCurve = new VelocityCurveModel();
        VelocityCurveModel _homeVelocityCurve = new VelocityCurveModel();
        public VelocityCurveModel DefaultVelocityCurve
        {
            get => _defaultVelocityCurve;
            set => SetProperty(ref _defaultVelocityCurve, value);
        }

        public double Tacc { get => _tacc; set { SetProperty(ref _tacc, value);  } }
        public double Tdec { get => tdec; set { SetProperty(ref tdec, value);  } }
        public double Maxvel { get => maxvel; set { SetProperty(ref maxvel, value); } }


        public VelocityCurveModel HomeVelocityCurve
        {
            get => _homeVelocityCurve;
            set => SetProperty(ref _homeVelocityCurve, value);
        }
        /// <summary>
        /// 回零偏移
        /// </summary>
        public double HomeOffset
        {
            get => _homeOffset;
            set => SetProperty(ref _homeOffset, value);
        }
        /// <summary>
        /// 当前实际运行速度
        /// </summary>
        public double CurrentSpeed => _axis.CurrentSpeed;
        /// <summary>
        /// 当前位置
        /// </summary>
        public double Current => _axis.Current;
        /// <summary>
        /// 脉冲当量
        /// </summary>
        public double Equivalent
        {
            get => _equivalent;
            set
            {
                if (SetProperty(ref _equivalent, value))
                    _axis.Equivalent = value;
            }
        }

        public bool IsAlm
        {
            get => _isAlm;
            private set => SetProperty(ref _isAlm, value);
        }

        public bool IsEmg
        {
            get => _isEmg;
            private set => SetProperty(ref _isEmg, value);
        }

        public bool IsMel
        {
            get => _isMel;
            private set => SetProperty(ref _isMel, value);
        }

        public bool IsOrg
        {
            get => _isOrg;
            private set => SetProperty(ref _isOrg, value);
        }

        public bool IsPel
        {
            get => _isPel;
            private set => SetProperty(ref _isPel, value);
        }
        public bool IsDone => _axis.IsDone;
        public AxisRunningMode RunningMode => _axis.RunningMode;
        public bool IsServoOn
        {
            get
            {
                try
                {
                    return _axis.IsServoOn;
                }
                catch { return false; }
            }
            set
            {
                try
                {
                    _axis.ServoOn(value);
                    RaisePropertyChanged(nameof(IsServoOn));
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }
        public IEnumerable<MotionPathModel> MotionPaths { get; set; }

        public bool IsParamEnable { get => isParamEnable; set => SetProperty(ref isParamEnable, value); }

        AxisDebugOption _debugOption;
        public AxisDebugOption DebugOption
        {
            get => _debugOption;
            set => SetProperty(ref _debugOption, value);
        }
        #endregion

        #region Commands

        public IRelayCommand OriginCommand { get; }
        public IRelayCommand ResetCommand { get; }
        public IRelayCommand ServonCommand { get; }
        public IRelayCommand StopCommand { get; }
        public IRelayCommand PositiveMoveCommand { get; }
        public IRelayCommand NagtiveMoveCommand { get; }
        public IRelayCommand PositiveJogMoveCommand { get; }
        public IRelayCommand NagtiveJogMoveCommand { get; }
        public IRelayCommand GotoCommand { get; }
        public IRelayCommand AbsoluteMoveCommand { get; }
        public IRelayCommand RelativeMoveCommand { get; }
        public IRelayCommand CopyTargetCommand { get; }

        public IRelayCommand UseDefaultSpeedCommand { get; }
        public IRelayCommand UseDefaulTaccCommand { get; }
        public IRelayCommand UseDefaultTdecCommand { get; }

        #endregion

        public AxisModel(DmcAxis axis, AxisOption option, ICommandFactory commandFactory, ITypeAdapter typeAdapter, AxisDebugOption debugOption)
        {
            _debugOption = debugOption;
            _axis = axis;
            _typeAdapter = typeAdapter;
            _typeAdapter.Adapt(option, this);
            OriginCommand = commandFactory.Create(Origin);
            ResetCommand = commandFactory.Create(Reset);
            ServonCommand = commandFactory.Create<bool>(Servon);
            StopCommand = commandFactory.Create(Stop);
            PositiveMoveCommand = commandFactory.Create(PositiveMove);
            NagtiveMoveCommand = commandFactory.Create(NagtiveMove);
            PositiveJogMoveCommand = commandFactory.Create(PositiveJogMove);
            NagtiveJogMoveCommand = commandFactory.Create(NagtiveJogMove);
            GotoCommand = commandFactory.Create<MotionPathModel>(MoveTo);
            AbsoluteMoveCommand = commandFactory.Create(AbsoluteMove);
            RelativeMoveCommand = commandFactory.Create(RelativeMove);
            UseDefaultSpeedCommand = commandFactory.Create(UseDefaultSpeed);
            UseDefaulTaccCommand = commandFactory.Create(UseDefaulTacc);
            UseDefaultTdecCommand = commandFactory.Create(UseDefaultTdec);
            CopyTargetCommand = commandFactory.Create<MotionPathModel>(CopyTarget);
            try
            {
                if(axis.Option?.MotionPaths?.Count>0)
                {
                    Tacc = axis.GetCurrentVelocityCurve().Tacc;
                    Tdec = axis.GetCurrentVelocityCurve().Tdec;
                }
                if (DefaultVelocityCurve == null)
                {
                    DefaultVelocityCurve = _typeAdapter.Adapt<VelocityCurveModel>(_axis.GetCurrentVelocityCurve());
                }
                if (HomeVelocityCurve == null)
                {
                    var result = _axis.GetHomeVelocityCurve();
                    HomeVelocityCurve = _typeAdapter.Adapt<VelocityCurveModel>(result.VelocityCurve);
                    HomeOffset = result.HomeOffset;
                }
            }
            catch { }

        }

        void UseDefaultSpeed()
        {
            MotionPaths.ForEach(x => x.VelocityCurve.Maxvel = Maxvel);
        }
        void UseDefaulTacc()
        {
            MotionPaths.ForEach(x => x.VelocityCurve.Tacc = Tacc);
        }
        void UseDefaultTdec()
        {
            MotionPaths.ForEach(x => x.VelocityCurve.Tdec = Tdec);
        }
        async Task Origin()
        {
            try
            {
                await _axis.MoveOriginAsync(_typeAdapter.Adapt<VelocityCurve>(HomeVelocityCurve), HomeOffset);
            }
            catch (Exception)
            {
                //await _messageService.ShowErrorAsync(ex.Message);
            }
        }

        private async Task NagtiveMove()
        {
            try
            {
                await _axis.NegativeAsync(new VelocityCurve() { Maxvel = DebugOption.ContinueSpeed, Tacc = 0.1, Tdec = 0.1 });
            }
            catch (Exception)
            {
                //await _messageService.ShowErrorAsync(ex.Message);
            }
        }

        private async Task PositiveMove()
        {
            try
            {
                await _axis.PostiveAsync(new VelocityCurve() { Maxvel = DebugOption.ContinueSpeed, Tacc = 0.1, Tdec = 0.1 });
            }
            catch (Exception)
            {
                //await _messageService.ShowErrorAsync(ex.Message);
            }
        }

        private async Task NagtiveJogMove()
        {
            try
            {
                await _axis.NegativeAsync(new VelocityCurve() { Maxvel = DebugOption.JogSpeed, Tacc = 0.1, Tdec = 0.1 });
            }
            catch (Exception)
            {
                //await _messageService.ShowErrorAsync(ex.Message);
            }
        }

        private async Task PositiveJogMove()
        {
            try
            {
                await _axis.PostiveAsync(new VelocityCurve() { Maxvel = DebugOption.JogSpeed, Tacc = 0.1, Tdec = 0.1 });
            }
            catch (Exception)
            {
                //await _messageService.ShowErrorAsync(ex.Message);
            }
        }

        async Task AbsoluteMove()
        {
            try
            {
                await _axis.MoveToAsync(DebugOption.AbsPosition, _typeAdapter.Adapt<VelocityCurve>(DefaultVelocityCurve));
            }
            catch (Exception e)
            {

            }
        }
        async Task RelativeMove()
        {
            try
            {
                await _axis.MoveDeltaAsync(DebugOption.RelPosition, _typeAdapter.Adapt<VelocityCurve>(DefaultVelocityCurve));
            }
            catch (Exception e)
            {

            }
        }

        /// <summary>
        ///     驱动轴运行到指定点位。
        /// </summary>
        async Task MoveTo(MotionPathModel motionPathModel)
        {
            try
            {
                VelocityCurve velocityCurve = _typeAdapter.Adapt<VelocityCurve>(motionPathModel.VelocityCurve);
                await _axis.MoveToAsync(motionPathModel.Target, velocityCurve);
            }
            catch (Exception)
            {
                //await _messageService.ShowErrorAsync(ex.Message);
            }
        }
        /// <summary>
        ///     轴状态重置。
        /// </summary>
        void Reset()
        {
            try
            {
                _axis.Reset();
            }
            catch (Exception)
            {
                //await _messageService.ShowErrorAsync(ex.Message);
            }
        }
        /// <summary>
        ///     轴励磁。
        /// </summary>
        /// <param name="isOn"></param>
        void Servon(bool isOn)
        {
            try
            {
                _axis.ServoOn(isOn);
            }
            catch (Exception)
            {
                //await _messageService.ShowErrorAsync(ex.Message);
            }
        }
        async Task Stop()
        {
            try
            {
                await _axis.PauseAsync();
            }
            catch (Exception)
            {

            }
        }
        private async void CopyTarget(MotionPathModel motionPathModel)
        {
            try
            {
                motionPathModel.Target = Current;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        /// <summary>
        ///     驱动轴运行到指定点位。
        /// </summary>
        public virtual void RefreshSates()
        {
            var status = _axis.Status;
            IsAlm = (status & AxisStatus.Alarmed) == AxisStatus.Alarmed;
            IsPel = (status & AxisStatus.PositiveLimit) == AxisStatus.PositiveLimit;
            IsMel = (status & AxisStatus.NegativeLimit) == AxisStatus.NegativeLimit;
            IsOrg = (status & AxisStatus.Origin) == AxisStatus.Origin;
            IsEmg = (status & AxisStatus.EmgStop) == AxisStatus.EmgStop;
            RaisePropertyChanged(nameof(IsDone));
            RaisePropertyChanged(nameof(RunningMode));
            RaisePropertyChanged(nameof(Current));
            RaisePropertyChanged(nameof(CurrentSpeed));
            _count++;
            if (_count > 10)
            {
                RaisePropertyChanged(nameof(IsServoOn));
                _count = 0;
            }
        }
        int _count = 0;
        private double tacc;
        private string channel;
    }
}
